#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
__title__ = ''
__author__ = 'HaiFeng'
"""
import sys
import os
import logging
import logging.handlers
#from pyecharts import Line, Kline
from collections import OrderedDict

sys.path.append(os.path.join(sys.path[0], '..'))  # 调用父目录下的模块

from py_at.Statistics import Statistics
from py_at.Enums import *
from py_at.Bar import *
from py_at.OrderItem import OrderItem
from py_at.adapters.ctp_trade import *
from py_at.adapters.ctp_quote import *
# from WindPy import *
from py_at.Data import Data
from py_at.Tool import *
from py_at.strategy import Strategy
from py_at.Enums import DirectType
import json
import time
#import pickle as pkl
import queue
from queue import Queue, Empty
from threading import Thread
import numpy as np
from py_at.publicMethod import roundToPriceTick   #最小单位处理
import copy
from py_at.Accounts.Account import Account as ctpAccount
from excange.okiapi.Client import Account as okAccount

class AdapterTest:
    """"""

    def __init__(self):
        """Constructor"""
        self.stra_instances = {}  # 策略接口
        self.q = None
        self.t = None
        self.TradingDay = ''
        self.real = False  # 控制实际下单
        self.CanshuDict = OrderedDict() # 所有策略集合
        self.allInstrument = []  # 所有合约名  用于前台显示使用
        self.instrumentPriceTick = []  # 所有合约最小跳
        self.logInfo = None
        self.tickStrategyDict = {}  # 所有策略和对应的合约   {'rb1708':['双均线实例','布林带实例'....]}
        self.Strageties_name_params = {}  # '所有可加载的策略名'和参数 用于前台ui用的
        self.LastTick = {}  # 订阅合约的最近价格 涨跌停价格等信息
        self.Accounts={} #所有登陆账户
        self.FuturesSetting ={} #期货公司
        self.active = False  # 工作状态
        self.queue = Queue()  # tick队列
        self.thread = Thread(target=self.run)  # tick线程
        self.autoSynchOrderThread = Thread(target=self.autoSynchOrderThread)  # 线程 每隔多少秒自动进行撤单并且同步

        self.WorkOrders=dict()  #活动的订单  未成交的活动订单

        settingFileName = 'CTA_setting.json'
        path = os.path.abspath(os.path.dirname(__file__))
        self.settingFileName = os.path.join(path, settingFileName)


        # 读取期货公司配置
        with open('{0}/{1}'.format(os.path.split(os.path.realpath(__file__))[0], 'Futures.json')) as f:
            self.FuturesSetting = json.load(f, object_pairs_hook=OrderedDict)

    # ---------------次数初始化日志
    def createlogInfo(self):
        console = logging.StreamHandler()
        console.setLevel(logging.INFO)
        formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
        console.setFormatter(formatter)
        logging.getLogger().addHandler(console)

        LOG_FILE = 'Celue.log'

        handler = logging.handlers.RotatingFileHandler(LOG_FILE, maxBytes=1024 * 1024, backupCount=5,
                                                       encoding="UTF-8")  # 实例化handler
        fmt = '%(asctime)s | %(filename)-12s:%(lineno)-5s | %(levelname)-8s | %(message)s'
        datefmt = '%Y-%m-%d %H:%M:%S'

        formatter = logging.Formatter(fmt, datefmt)  # 实例化formatter
        handler.setFormatter(formatter)  # 为handler添加formatter

        logger = logging.getLogger('Celue')  # 获取名为tst的logger
        logger.addHandler(handler)  # 为logger添加handler
        logger.setLevel(logging.DEBUG)
        self.logInfo = logging.getLogger('Celue')




#-------------------------------------------------------------------------------------------------------------从策略调用到ctp相关信息
    def get_orders(self,stra,t):# 从策略类调用到这里 获取当前策略的当前账户的所有委托
        """
        :param stra: 策略
        :param t:    账户
        :return:
        """
        rtn = []
        for (k, v) in t.t.DicOrderField.items():
            if v.Custom // 1000 == stra.OrderStrateId:
                rtn.append(v)
        return rtn

    def get_lastorder(self, stra,t):
        """获取策略最后一个委托"""
        rtn = self.get_orders(stra,t)
        if len(rtn) > 0:
            sorted(rtn, key=lambda o: o.Custom)
            return rtn[-1]
        return None

    def get_notfill_orders(self, stra,t):
        """获取策略未成交委托"""
        rtn = []
        orders = self.get_orders(stra,t)
        if len(orders) > 0:
            for order in orders:
                if order.Status == OrderStatus.Normal or order.Status == OrderStatus.Partial:
                    rtn.append(order)
        return rtn

    def cencelById(self,id,t):
        """
        撤单
        :param id:
        :param t:
        :return:
        """
        t.ReqOrderAction(id)

    def req_order(self, instrument: str, dire: DirectType, offset: OffsetType, price: float, volume: int, type: OrderType = OrderType.Limit, stra: Strategy = ''):
        """发送委托"""
        pass
        # order_id = stra.ID * 1000 + len(stra.GetOrders()) + 1
        # # 价格修正
        # price = price // self.t.instruments[instrument].PriceTick * self.t.instruments[instrument].PriceTick
        # self.t.ReqOrderInsert(instrument, dire, offset, price, volume, type, order_id)

    def cancel_all(self, stra,t):
        """撤销所有委托"""
        for order in self.get_notfill_orders(stra,t):
            t.ReqOrderAction(order.OrderID)


    # -------此处调用ctp接口即可实现实际下单---------------------------------------------------------------
    def on_order(self, stra,data, order):
        """strategy's order"""
        p = stra
        if p != None:  # 账户已经登陆完成  如果是策略发的单子
            if (self.real and stra.EnableOrder):  # 那么就开始仔细排查是否开启了实盘 如果开启了就执行
                #self.logInfo.info("{0}发送订单".format(stra.ID))
                self.logInfo.info(
                    '发送单子{0}\t{1}\t{2}\t{3}\t{4}'.format(type(stra), order.DateTime,
                                                                         order.Price,
                                                                        order.Volume, order.Remark))
                for user, vol in stra.Investors.items():  # 循环遍历对所有这个策略配置的所有账户根据当时的定义倍数进行下单
                    if not self.Accounts.get(user):  # TODO 如果策略配置的这个账户没有登陆  那么直接跳过本次循环
                        print('策略配置了  但是交易账户没有登陆')
                        continue
                    else:
                        ordertemp = copy.deepcopy(order)              #不改变原始order的倍数所以这里拷贝
                        ordertemp.Volume = order.Volume * vol  # 报单根据每个账户设置不同的倍数
                        print('报单价格%s' %ordertemp.Price)
                        ordertemp.Price = roundToPriceTick(stra.PriceTick,ordertemp.Price)
                        print('价格调整以后%s' %ordertemp.Price)
                        order_id = int(stra.OrderStrateId) * 1000+ len(stra.GetOrders(self.Accounts.get(user))) + 1  #根据每个账户生成不同的报单编号这里可能不是很稳妥
                        print("订单号为%s" %order_id)
                        self.send_order(self.Accounts.get(user), ordertemp,order_id)

    def send_order(self,user,order,order_id):
        """
        下单函数  自动进行实盘仓位确认以及平昨平今转换
        :param user:下单的账户
        :param order: 下单的order信息
        :return:
        """

        dire = DirectionType.Buy if order.Direction == DirectType.Buy else DirectionType.Sell

        if order.Offset != OffsetType.Open:  # 如果发单是平仓单子
            key = '{0}_{1}'.format(order.Instrument,
                                   int(DirectType.Sell if order.Direction == DirectType.Buy else DirectType.Buy))
            # 无效,没提示...pf = PositionField()
            # 实盘仓位检查
            pf = user.t.DicPositionField.get(
                key)  # 在ctp_trade.py里面  一个在持仓回报中  一个在资金查询回报中  这里的意思是查询一下仓位看下今仓的意思
            if not pf or pf.Position <= 0:
                self.logInfo.info('实盘仓位检查---------没有对应的持仓')
                self.logInfo.info(key)
                self.logInfo.info(user.t.DicPositionField.get(key))
            else:
                volClose = min(pf.Position, order.Volume)  # 可平量
                instField = user.t.DicInstrument[order.Instrument]
                if instField.ExchangeID == 'SHFE':
                    tdClose = min(volClose, pf.TdPosition)  # 今仓和可平量取最小值
                    if tdClose > 0:  # 今仓如果大于0  那么发平今仓
                        user.t.ReqOrderInsert(order.Instrument, dire, OffsetType.CloseToday, order.Price,
                                                          tdClose,
                                                          OrderType.Limit, order_id)
                        volClose -= tdClose
                if volClose > 0:  # 最后如果没有平今  那么就平昨
                    user.t.ReqOrderInsert(order.Instrument, dire, OffsetType.Close, order.Price, volClose,
                                                      OrderType.Limit, order_id)
        else:
            user.t.ReqOrderInsert(order.Instrument, dire, OffsetType.Open, order.Price, order.Volume,
                                              OrderType.Limit, order_id)




    #-----------------------------------------------------------------------------------
    def readInverstorsjson(self):
        """
        :return: 返回账户配置json格式
        """
        sysstr = platform.system()
        if (sysstr == "Windows"):
            mulu = '{0}\{1}'
        elif (sysstr == "Linux"):
            mulu = '{0}/{1}'
        with open(mulu.format(os.path.split(os.path.realpath(__file__))[0], 'Investors.json')) as f:
            InvestorSetting = json.load(f)
        return InvestorSetting

    # ----------------------------------------------------------------------
    def write_strategy_json(self, celue):
        """
        添加策略配置到json文件  并且添加到内存中
        :param celue: 配置对象信息
        :return: 然后当前配置
        """
        tme_json = OrderedDict()
        tme_json['ID'] = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))

        tme_json['OrderStrateId'] = 1
        tme_json['InitFund'] = 10000
        tme_json['Strategy'] = celue['selectedstrategName']
        tme_json['BeginDate'] = "20181218"
        tme_json['Backtest'] = "true"
        tme_json['Excange'] = celue['selectedstrategExcange']
        tme_json['Comment'] = ""
        tme_json['Datas'] = [{
            'Instrument':celue['selectedinstrumentName'],
            'Interval':int(celue['Zhouqi']),
            'IntervalType':celue['selectedIntervalType'].split('.')[1] #'IntervalType.Tick'   格式化为'Tick'
        }]

        tme_json['Params'] = (eval(celue['strategParameter']))
        tme_json['Investors']={"104147":1}

        l = self.open_option_file(self.settingFileName)  #从内存中读取所有配置侧露
        #生成最大报单编号
        maxorder = 0
        for i in l:
            if i['OrderStrateId']>maxorder:
                maxorder = i['OrderStrateId']
        tme_json['OrderStrateId'] = maxorder+1;
        #生成最大保单编号

        l.append(tme_json)                          #把当前策略添加到配置文件中
        self.write_option_file(self.settingFileName,l) #持久化配置文件
        self.CanshuDict[tme_json['ID']] = tme_json      #添加到内存中
        return tme_json
    # -----------------------------------------------------------------------
    def load_strategy_json(self):
        """
        加载所有配置文件到内存中 不返回内容 直接加载
        :return:
        """
        l=self.open_option_file(self.settingFileName)
        if(len(l)):
            for setting in l:
                self.CanshuDict[setting['ID']] = setting
        else:
            print('应该没有策略配置')


    # ------------------------------------------------------------------------------------
    def updateParams(self,id,paramsname,params):
        '''
        更新策略参数
        :param id:
        :param params:
        :return:
        '''
        l = self.open_option_file(self.settingFileName)
        # 读取  并且找到删除
        for i in l:
            if i.get("ID") == id:      #查找id
                i[paramsname] = params  #更新params
                break
        self.write_option_file(self.settingFileName, l)  # 重新写入配置文件
        self.CanshuDict[id][paramsname] = params

        if(paramsname=='Params'):                 #如果修改的参数  那么就需要重新加载  所以设置策略为未初始状态 为空
            self.CanshuDict[id]['stra'] = None  # 初始化交易状态为空  也就是完全停止交易

    def deletestra(self, straid):
        """
        删除当前策略配置 从内存和配置文件中一块删除当前策略
        :param straid:
        :return:
        """
        l = self.open_option_file(self.settingFileName)
        # 读取  并且找到删除
        for i in l:
            if i.get("ID") == straid:
                l.remove(i)
        self.write_option_file(self.settingFileName,l)  #重新写入配置文件
        self.CanshuDict.pop(straid)

    # ---------------------------------------------------------------------------
    def load_strategyname(self):
        """加载../strategy目录下的策略 并且返回"""

        """通过文件名取到对应的继承Data的类并实例"""
        # for path in ['strategies', 'private']:
        self.Strageties_name_params = {}  # 清空  防止重复加载

        for path in ['strategies']:


            filepath = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
            files= os.path.join(filepath, path)
            files = os.listdir(files)
            #files = os.listdir("../{0}/".format(path))



            #
            # if not os.getcwd()[-3:]=='rpc':     #默认启动 使用的普通方式
            #     files = os.listdir("../{0}/".format(path))
            # else:                                                   #使用rpc模式启动
            #     files = os.listdir("../../{0}/".format(path))


            for f in files:
                if os.path.isdir(f) or os.path.splitext(f)[0] == '__init__' or os.path.splitext(f)[-1] != ".py":
                    continue
                # 目录结构???
                module_name = "{1}.{0}".format(os.path.splitext(f)[0], path)
                class_name = os.path.splitext(f)[0]
                module = __import__(module_name)  # import module

                c = getattr(getattr(module, class_name), class_name)  # 双层调用才是class,单层是为module

                if not issubclass(c, Strategy):  # 类c是Data的子类
                    continue
                objtem = c("")  # new class
                self.Strageties_name_params[class_name] = objtem.Params  #得到默认参数  用于初始化ui
                self.stra_instances[class_name] = c   # 把当前类放进策略接口dict里面
                objte = None

    # ---------------------------------------------------------------------------
    def initstra(self, straid):
        """
        加载当前的策略
        :param straid:  需要初始的id
        :return:如果正确不返回任何消息--错误了才返回消息
        """
        if self.CanshuDict.get(straid):  # 从策略配置中找到这个条策略配置
            tempcanshu = self.CanshuDict.get(straid)
            if (self.stra_instances.get(tempcanshu['Strategy'])):  # 从接口dict里面找到当前策略配置使用的Strategy

                # # 原来使用的是注入的方式 也是很经典的
                # for k, v in tempcanshu.items():
                #     if k in obj.__dict__:
                #         obj.__setattr__(k, eval(v)) if k == 'IntervalType' else obj.__setattr__(k, v)

                # 动态为策略增加两个属性  一个是最小跳 一个是交易时段
                obj = self.stra_instances.get(tempcanshu['Strategy'])(tempcanshu)  # new class  实例化当前所选配置
                obj.PriceTick = [i for i in self.allInstrument if i['InstrumentID'] == obj.Instrument][0].get(
                    'PriceTick')  # 得到最小交易价格以及单位
                obj.VolumeMultiple = [i for i in self.allInstrument if i['InstrumentID'] == obj.Instrument][0].get(
                    'VolumeMultiple')  # 得到交易单位


                if obj.Excange=="CTP":                                #用于ctp的初始化
                    if obj.IntervalType == IntervalType.Tick:  # tick单独加载  属于不同的加载通道
                        ctpAccount.read_tick_test(obj)  # 调用ctp静态方法加载tick数据
                    else:
                        ctpAccount.read_data_test(obj)  # 调用ctp静态方法加载分钟数据

                elif obj.Excange=="OKEX":                      #用于虚拟货币的初始化
                    okAccount.read_data_test(obj)            #调用虚拟货币静态方法加载数据

                tempcanshu['stra'] = obj                          #设置tempcanshu['stra']对象 进行赋值  这里等于是对self.CanshuDict.get(straid)进行赋值
                if obj.Instrument in self.tickStrategyDict:  # 如果已经订阅过了 那么直接添加进列表就行了  否则就创建一个列表
                    self.tickStrategyDict[obj.Instrument].append(obj)          #{'rb1901':[Boll,Ma,reboot]}
                else:
                    self.tickStrategyDict[obj.Instrument] = [obj]
                    if self.q:                 # 如果行情存在  那么订阅ctp 和 虚拟货币都有这个方法
                        self.q.ReqSubscribeMarketData(obj.Instrument)  # 加载之后直接订阅合约

            else:
                return "策略加载失败 未找到相应策略模板"



    #--------------------------------------------------------------------------------
    def link_fun(self,stratemp):
        '''策略函数与实盘函数关联 '''
        stratemp._data_order = self.on_order                   #从策略类调用到这里 执行下单操作
        stratemp._get_orders = self.get_orders                 #从策略类调用到这里 获取当前策略的所有订单
        stratemp._get_lastorder = self.get_lastorder           #从策略类调用到这里 获取最后一个委托
        stratemp._get_notfill_orders = self.get_notfill_orders   #从策略类调用到这里 获取所有未成交委托
        stratemp._req_order = self.req_order                      #从策略类调用到这里 发送订单
        stratemp.ReqCancel = self.cencelById               #从策略类调用到这里 撤单
        stratemp._req_cancel_all = self.cancel_all               #从策略类调用到这里 撤销全部订单

    # ---------------------------------------------------------------------------------
    def trading(self, straid, bolltem="True"):
        """
        绑定或者解除实盘下单
        :param straid:  策略id
        :param bolltem: 实盘标志
        :return:如果正确不返回任何消息  错误了返回
        """

        if self.CanshuDict.get(straid):
            temp = self.CanshuDict.get(straid)
            if temp.get('stra'):
                self.real = True
                tempobj = temp.get('stra')
                self.link_fun(tempobj)     #绑定所有账户主动以及被动函数  暂时只有ctp适用
                tempobj.EnableOrder = eval(bolltem)
                return""
            else:
                return " %s策略是否没有加载"%straid
        else:
            return " %s没有找到当前ID的策略"%straid



    # --------------------------------------------------------------------------------
    def selectPosition(self,user):
        #TODO 暂时只用了user一个参数 其他两个没有使用
        """
        查询逻辑持仓和实际持仓信息
        :param tiaojian: user 选择的用户
                          instrument 选择的商品
        :return: 如果正常返回仓位信息  否则返回处理信息
        """
        AccountPosition = {}  # 实盘
        StrategPosition = {}  # 策略
        Positions = {}

        # 查找并构建当前user  实盘仓位查询
        for key, var in self.Accounts[user].t.DicPositionField.items():  # 处理格式为{'p1801': {'0': 3, '1': 1}, 'TA801': {'0': 1, '1': 1}, 'MA709': {'1': 6}, 'rb1710': {'0': 2, '1': 2}, 'hc1710': {'0': 0, '1': 2}}
            #构造成合适的dict
            if AccountPosition.get(key[0:key.find("_")]):
                AccountPosition[key[0:key.find("_")]][key[key.find("_") + 1]] = var.Position
            else:
                AccountPosition[key[0:key.find("_")]] = {}
                AccountPosition[key[0:key.find("_")]][key[key.find("_") + 1]] = var.Position

        # 查找并构建user所有策略仓位
        for i in self.CanshuDict.values():   #遍历所有策略
            if i.get('stra') and i.get('stra').EnableOrder == True and user in i.get('Investors'):  #如果是已经启动 那么进行仓位统计
                stra = i.get('stra')
                if (StrategPosition.get(stra.Instrument)):  # 如果存在
                    StrategPosition[stra.Instrument]['0'] = StrategPosition[stra.Instrument]['0'] + stra.PositionLong * i.get('Investors')[user]
                    StrategPosition[stra.Instrument]['1'] = StrategPosition[stra.Instrument]['1'] + stra.PositionShort * i.get('Investors')[user]
                else:  # 如果不存在 创建一个
                    StrategPosition[stra.Instrument] = {'0': stra.PositionLong * i.get('Investors')[user], '1': stra.PositionShort * i.get('Investors')[user]}  # 0多  1空

        # 构造显示页面的dict  只用启动的策略才进行仓位对比
        for key, var in AccountPosition.items():

            if key in StrategPosition:    #如果策略仓位中存在 那么才使用  排除有些时候客户使用手工自己操作的仓位被这个同步掉
                Positions[key] = {'AccountId':user,'Instrument': key, 'AccountPosition': var.get('0', 0) + var.get('1', 0) * -1,
                                  'StrategyPosition': 0, 'disparity': 0, 'AccountBuy': var.get('0', 0),
                                  'StrategyBuy': 0,
                                  'AccountShort': var.get('1', 0) * -1, 'StrategyShort': 0}
        # 填充显示dict

        for key, var in StrategPosition.items():
            if Positions.get(key):  # 如果实际仓位存在
                Positions[key]['StrategyPosition'] = var['0'] + var['1'] * -1
                Positions[key]['disparity'] = Positions[key]['AccountPosition'] - Positions[key]['StrategyPosition']
                Positions[key]['StrategyBuy'] = var['0']
                Positions[key]['StrategyShort'] = var['1']

            else:  # 如果实际仓位不存在
                Positions[key] = {'AccountId':user,'Instrument': key, 'AccountPosition': 0, 'StrategyPosition': var['0'] + var['1'] * -1,
                                  'disparity': var['0'] + var['1'] * -1,
                                  'AccountBuy': 0, 'StrategyBuy': var['0'], 'AccountShort': 0,
                                  'StrategyShort': var['1']}


        return Positions
        # ------------------------------------------------------------------------------------------------

    def synchronous(self,positionlist):
        '''

        :param positionlist:  需要同步的所有仓位list
        [
    {
      "rb1905": {
        "AccountBuy": 2,
        "AccountId": "104147",
        "AccountPosition": -5,
        "AccountShort": -7,
        "Instrument": "rb1905",
        "StrategyBuy": 1,
        "StrategyPosition": 1,
        "StrategyShort": 0,
        "disparity": -6
      },
      "ru1905": {
        "AccountBuy": 1,
        "AccountId": "104147",
        "AccountPosition": 1,
        "AccountShort": 0,
        "Instrument": "ru1905",
        "StrategyBuy": 1,
        "StrategyPosition": 1,
        "StrategyShort": 0,
        "disparity": 0
      }
    }
  ]，    [
    {
      "rb1905": {
        "AccountBuy": 2,
        "AccountId": "021564",
        "AccountPosition": -5,
        "AccountShort": -7,
        "Instrument": "rb1905",
        "StrategyBuy": 1,
        "StrategyPosition": 1,
        "StrategyShort": 0,
        "disparity": -6
      },
      "ru1905": {
        "AccountBuy": 1,
        "AccountId": "021564",
        "AccountPosition": 1,
        "AccountShort": 0,
        "Instrument": "ru1905",
        "StrategyBuy": 1,
        "StrategyPosition": 1,
        "StrategyShort": 0,
        "disparity": 0
      }
    }
  ]
        :return:
        '''
        #Positions = self.selectPosition(user)  # 调用查询得到当前仓位
        #user = self.Accounts[user]

        for accountposition in positionlist:
            for v in accountposition.values():
                vol = v['StrategyBuy'] - v['AccountBuy']  # 如果策略比实盘多   那么开多   如果实盘比策略多  那么平
                if vol > 0:
                        self.SendOrder(self.Accounts[v['AccountId']], v['Instrument'], DirectType.Buy, OffsetType.Open, self.LastTick[v['Instrument']].AskPrice, abs(vol),
                                   '买开')
                if vol < 0:
                    self.SendOrder(self.Accounts[v['AccountId']], v['Instrument'], DirectType.Sell, OffsetType.Close, self.LastTick[v['Instrument']].BidPrice, abs(vol),
                                   '卖平')
                vol = abs(v['StrategyShort']) - abs(v['AccountShort'])  # 如果策略比实盘多   那么开   如果实盘比策略多  那么平
                if vol > 0:
                    self.SendOrder(self.Accounts[v['AccountId']], v['Instrument'], DirectType.Sell, OffsetType.Open, self.LastTick[v['Instrument']].BidPrice, abs(vol),
                                   '卖开')
                if vol < 0:
                    self.SendOrder(self.Accounts[v['AccountId']], v['Instrument'], DirectType.Buy, OffsetType.Close, self.LastTick[v['Instrument']].AskPrice, abs(vol),
                                   '买平')


    # ---------------------------------------------------------------------------------------------
    def SendOrder(self, user,Instrument, Direction, Offset, Price, Volume, Remark, ):
        """
        用于仓位同步发送单子  不经过策略层面  经过策略层了 就会出现position增加或者减少的问题 比较麻烦 所以单独拿出来
        :param Instrument:
        :param Direction:
        :param Offset:
        :param Price:
        :param Volume:
        :param Remark:
        :return:
        """
        order = OrderItem()
        order.Instrument = Instrument
        order.Direction = Direction
        order.Offset = Offset
        order.Price = Price
        order.Volume = Volume
        order.Remark = Remark
        self.send_order(user, order,0)  # 直接发送订单进行发单  这个不经过策略

    # ----------------------------------------------------------------------------
    def load_all_Instrument(self):
        """原来是从海风  后面改成变成从交易所了 这样更加稳定 加载所有合约以及所有合约的最小跳数据"""
        # self.allInstrument = [i for i in read_from_mq(Type=6) if
        #                       (len(i['_id']) <= 7 and len(i['_id']) > 1) and 'efp' not in i['_id']]  # 去掉不规整数据
        # self.allInstrument.sort(key=lambda k: (k.get('_id', 0)))  # 排序
        # self.instrumentPriceTick = read_from_mq(Type=4)  # 得到合约信息
        # self.shiduan = read_from_mq(Type=3)       #得到所有交易时段



        FileName = 'DicInstrument.json'
        path = os.path.abspath(os.path.dirname(__file__))
        filename = os.path.join(path, FileName)
        # if not os.getcwd()[-3:]=='rpc':  #本模块调用
        #     filename='DicInstrument.json'
        # else:                                           #其他模块方式加载rpc  或者run模式
        #     filename ='../DicInstrument.json'

        with open(filename, 'r') as f:   #默认使用rpc模式启动
            tempInstrument = json.load(f)
        self.allInstrument = [v for v in tempInstrument.values()]

        self.allInstrument.sort(key=lambda k: (k.get('InstrumentID'), 0))



        #增加虚拟货币  把各个交易所的最小跳等等信息都放这里 也可以放到各自的对象里面
        for i in ['btc_usd', 'ltc_usd', 'eth_usd', 'etc_usd', 'bch_usd', 'xrp_usd', 'eos_usd', 'btg_usd']:
            self.allInstrument.append({'InstrumentID': i, 'VolumeMultiple': 1, 'PriceTick': 1})





    #往下是账户相关的操作
    #TODO 这个地方是否能再进行一层抽象  完全的隔离开   账户登陆成功之后需要注册所有账户已持仓产品  这个功能还没有实现
    def TradeInit(self,key):
        #读取账户配置
        if(key in self.Accounts):
            return

        # with open('{0}/{1}'.format(os.path.split(os.path.realpath(__file__))[0],'Investors.json')) as f:
        #     InvestorSetting=json.load(f,object_pairs_hook=OrderedDict)
        InvestorSetting = self.readInverstorsjson()  # 读取配置文件



        #对当前账户进行登陆
        a = InvestorSetting[key]
        if not a.get('exchange'):                    #ctp登陆
            dome = ctpAccount(a['Investor'],a['Password'],self.FuturesSetting[a['Futures']]['BrokerID'],self.FuturesSetting[a['Futures']]['FrontID'],self.FuturesSetting[a['Futures']]['QFrontID'])
            dome.t.OnRspQryPosition = self.t_OnRspQryPosition    #持仓回报
            dome.t.OnRspQryAccount = self.t_OnRspQryAccount      #账户资金查询
            dome.t.OnRtnOrder = self.t_OnRtnOrder                #订单回报
            dome.t.OnRtnTrade = self.t_OnRtnTrade               #成交回报
            dome.t.OnRtnErrOrder =self.t_OnRtnErrOrder             #错误回报
        else:                                         #okex登陆
            # 读取账户配置
            dome = okAccount(a['apikey'], a['secretkey'], a['url'], a['positiontype'], key)
            dome.On_futur_userinof = self.t_OnRspQryAccount   # 不管是全仓还是半仓都回调到一个函数上  然后往前台传送
            dome.On_future_position = self.t_OnRspQryPosition # 这一个函数同时满足逐仓和全仓模式
            dome.On_future_order_info = self.t_OnRtnOrder  # 这一个订单函数

            dome.future_userinfo(True)    #直接开启仓位定时检查
            dome.future_position()        #这里是开启仓位定值检查   也可以使用手动查询 在前台
            dome.future_order_info()


        self.Accounts[key] = dome  #put进登陆账户list  列表


        #如果登陆账户大于1   初始化一个行情进行驱动策略  其他的账户不需要行情即可
        if not self.q:                  #如果行情不存在
            self.q = self.Accounts[list(self.Accounts.keys())[0]]  # 第一个账户的行情赋值为全局行情
            self.thread.start()  # 启动tick 任务
            if  not a.get('exchange'):   #虚拟货币才有这个属性  所以是ctp     ctp进行行情绑定    再行情回调里面订阅所有加载数据
                self.q.q.ReqConnect(self.q.QFfontID)
                self.q = self.q.q  # 全局行情对象赋值 简短使用
                self.q.OnRspUserLogin = self.q_OnRspUserLogin  # 绑定到本地函数
                self.q.OnRtnTick = self.q_Tick  # 绑定到本地函数  api回调函数变成这里自己定义的函数 这
            else:                         #虚拟火币行情绑定  直接进行绑定并订阅合约
                self.q.On_Ticker = self.q_Tick  # 上面是绑定k线的  这个是绑定tick的
                for canshu in self.CanshuDict.values():
                    if canshu.get('stra'):  # 如果策略已经初始化过了  订阅这个合约
                        print("订阅合约%s" %canshu['stra'].Instrument)
                        self.q.ReqSubscribeMarketData(symbol=canshu['stra'].Instrument)  # 订阅实时行情



    #下面是使用账户回调引发的--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    def q_on_tick(self,tick):
        """
        tick 往前台实现
        前台通讯函数 需要前台进行实现
        :param tick:
        :return:
        """
        pass

    def t_OnRspQryPosition(self,Positions):
        """
        持仓查询回调  暂时用于前台显示 ctp 和 ok共同
        :param Positions:
        :return:
        """
        pass            #持仓查询回调
    def t_OnRspQryAccount(self,Account):
        """
        资金查询回调   暂时用于前台显示 ctp 和 ok共同
        :param Account:
        :return:
        """
        pass   #资金查询回调
    def t_OnRtnOrder(self, OrderField):
        """
        订单回报    暂时用于前台显示 ctp 和 ok共同
        :param OrderField:
        :return:
        """
        pass
    def t_OnRtnTrade(self,TradeField):
        """
        成交回报
        :param TradeField:
        :return:
        """
        pass
    def t_OnRtnErrOrder(self,f=OrderField, info=InfoField):
        """
        错误回报
        :param f:
        :param info:
        :return:
        """
        pass

    #-------------------------------------------------------------------------------上面是交易回调  这里是行情回调-----------------------------------------------------------------------------------------

    def q_OnRspUserLogin(self, info=InfoField):
        """"""
        print('行情服务器登陆成功 信息如下')
        print(info)
        print('开始逐个策略订阅合约')  #策略里面配置的有当前合约
        for canshu in self.CanshuDict.values():
            if canshu.get('stra'):  # 如果策略已经初始化过了  订阅这个合约
                print(canshu['stra'].Instrument)
                self.q.ReqSubscribeMarketData(canshu['stra'].Instrument)


    def q_Tick(self, field=Tick):
        """
        得到tick全部存入到queue   主要是怕这里直接运行策略会出现阻塞 而放到queue里面再开一条线程 就不怕这里会出问题了
        :param field:
        :return:
        """
        print(field)
        self.queue.put((field))

    # -------------------------------------------------------------------------------------------
    def run(self):
        """进行策略tick  如果以后多了可是增加个线程池"""
        while True:
            try:
                field = self.queue.get(block=True, timeout=1)
                self.LastTick[field.Instrument] = field  #记录最后一个last tick 价格
                if field.Instrument in self.tickStrategyDict:
                    l = self.tickStrategyDict[field.Instrument]
                    for stra in l:
                        for data in stra.Datas:
                            if data.Instrument == field.Instrument:
                                stra.Datas[0].on_tick(field)

                    self.q_on_tick(field)  # 前台通讯函数  看看会不会出现断连 如果存在那么放到策略加载之前怎么样呢
            except Empty:
                pass
   #------------------------------------------------------------------------------------------------
    def register(self, func):
        """把这个函数注册到sock端口中  然后直接发送客户端"""
        self.func = func  # 谁想使用这个数据就从外部注入进来   使用方法register(自定义函数)   等于直接把信息传送到各个客户机
    # --------------------------------------------------------------------------------
    # def printkline(self, star):
    #     '''打印k线原来遗留得 现在没什么用了
    #     :param star:
    #     :return:
    #     '''
    #     v1 = [star.O.tolist(), star.H.tolist(), star.L.tolist(), star.C.tolist()]
    #
    #     v1 = list(map(list, zip(*v1)))
    #     attr = star.D.tolist()
    #     kline = Kline("Kline - Line 示例")
    #     kline.add("日K", attr, v1, mark_point=["max"], is_datazoom_show=True)
    #     kline.show_config()
    #     kline.render(r"e:\my_first_chart.html")

    # ----------------------------------------------------------------------------------------------
    def open_option_file(self,fileName):
        """
        读取配置文件并返回数组
        :return:配置文件数组
        """
        with open(fileName,encoding='utf-8') as f:
            try:
                l = json.load(f, encoding='utf-8',object_pairs_hook=OrderedDict)
            except Exception:
                l = []
        return l
        # -------------------------------------------------------------------------------------------------

    def write_option_file(self,fileName, l):
        """
        写入配置文件
        :param l:   传输过来的配置文件
        :return: 无返回
        """
        with open(fileName, 'w') as f:
            json.dump(l, f, indent=len(l[0].keys()))

    #-----------------------------------------------------------------------------------------------------------
    def autoSynchOrderThread(self):
        """每隔多少秒 查找所有未成功的订单   撤掉 然后重新按照策略仓位进行同步"""
        while True:
            if self.Accounts:
                for userid,user in self.Accounts.items():
                    for orderid,order in user.t.DicOrderField.items():
                        if order.Status== OrderStatus.Normal or order.Status == OrderStatus.Partial:
                            user.t.ReqOrderAction(orderid)
                            print(order)
                            print("上面是本次撤销的单子")
                    sleep(20)

                    self.synchronous("",userid,"")   #根据账户区分 那个策略属于那个账户  进行同步
                    print("仓位轮询并自动同步 %s" %time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))


from py_at.rpc.server import *

if __name__ == '__main__':


    #前端后端分离
    #eventEngine = mainEngine = AdapterTest()
    #reE = ReEngine(mainEngine, eventEngine)

    a = AdapterTest()
    a.TradeInit("104147")
    #a.load_strategy_json()  # 加载所有策略配置文件
    #a.load_strategyname()  # 加载所有策略模板类（也可以叫接口类）并且实例化并保存
    #a.load_all_Instrument()  # 加载所有合约信息


    #a.initstra("20190128143210")  # 初始化策略
    #a.trading("20190128143210")    #启动#实盘交易
    time.sleep(5)
    a.createlogInfo()  # 创建实盘日志
    print("发送订单")
    a.SendOrder(a.Accounts['104147'], 'rb1905', DirectType.Buy, OffsetType.Open, 3500, abs(1),
                   '买开')


    #a.autoSynchOrderThread.start()   #启动自动同步(这个功能需要改进  如果这个商品属于开盘范围那么进行发单 否则就不要进行发单)
    input()


    # shiduan=read_from_mq(Type=3)
    # #print(shiduan)
    # for i in shiduan:
    #     if i['GroupId']=='RM':
    #         rmshiduan= i['WorkingTimes']
    #         print(rmshiduan)
    #
    # shijian='10:29:00'
    # for i in rmshiduan:
    #     if shijian>=i['Begin'] and shijian<=i['End']:
    #         print("范围之内")
    #     print(i)

    # shijian='20:01:00'
    # if shijian>='21:00:00' and shijian<='23:00:00':
    #    print('a')
    # ShiDuan = [i['WorkingTimes'] for i in read_from_mq(Type=3)  if i['GroupId']==''.join([i for i in 'TA809' if i not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']])]
    # #ShiDuan = [i['WorkingTimes'] for i in read_from_mq(Type=3) if i['GroupId'] == 'RM']
    # print(ShiDuan)
